package core.generatingcode;

import core.db.DbHelper;
import core.db.util.LogUtils;
import core.db.util.TextUtils;
import entity.ApiAction;
import entity.ApiRoot;
import util.CommonUtil;
import util.DateUtil;
import util.JsonXmlUtils;
import util.json.JsonMananger;

import java.io.File;
import java.io.IOException;
import java.util.*;

public class GeneratingJava {
    /**
     * 解析
     * @param basePath
     * @param apiAction
     * @param onCallback
     */
    public static void generating(String basePath, ApiAction apiAction, OnCallback onCallback){
        List<ApiAction> actionList = new ArrayList<>();
        actionList.add(apiAction);
        generating(basePath,actionList,onCallback);
    }

    /**
     * 解析
     * @param basePath
     * @param apiActions
     * @param onCallback
     */
    public static void generating(String basePath,List<ApiAction> apiActions, OnCallback onCallback){
        //跟路径
        List<ApiRoot> apiRoots = DbHelper.findAll(ApiRoot.class);
        String date = DateUtil.format(new Date(),null);

        String usePackage = "com.gree.shyun";
        String actionsPath = basePath+"/server/actions";
        int count = 0 ;
        int has = 0;
        for(int i = 0 ;i<apiActions.size();i++) {
            ApiAction apiAction = apiActions.get(i);
            String url = apiAction.getUrl();
            String className = getClassNameByUrl(url);
            //String classPath = getClassPathByUrl(url);
            //请求参数
            try {
                String path;
                String alias = apiAction.getAlias();
                if(TextUtils.isEmpty(alias)){
                    alias = CommonUtil.getAlias(apiAction.getUrl());
                }
                //生成request参数
                Map<String, String> requestModel = null;
                List<String> packages = new ArrayList<>();
                if(!TextUtils.isEmpty(apiAction.getRequest())) {
                    path = actionsPath+"/"+alias+ "/request/";
                    File file = new File(path);
                    if (!file.exists()) {
                        file.mkdirs();
                        requestModel= JsonToModel.generate(className + "Request", apiAction.getRequest());
                        count += writeFile(requestModel, path);
                        for(String key:requestModel.keySet()){
                            packages.add(key);
                        }
                    } else {
                        has++;
                    }
                }

                //生成url请求参数
                Map<String, String> urlModel = null;
                if(!TextUtils.isEmpty(apiAction.getUrlParam())) {
                    path = actionsPath +"/"+alias+ "/requestParam/";
                    File paramFile = new File(path);
                    //url参数
                    if (!paramFile.exists()){
                        paramFile.mkdirs();
                        urlModel= JsonToModel.generate(className + "Param", apiAction.getUrlParam());
                        count += writeFile(urlModel, path);
                        for(String key:urlModel.keySet()){
                            packages.add(key);
                        }
                    }else{
                        has++;
                    }
                }

                Map<String, String> responeModel = null;
                //生成respone实体
                if(!TextUtils.isEmpty(apiAction.getRespone())) {
                    path = actionsPath +"/"+alias+ "/respone/";
                    File responeFile = new File(path);
                    //返回数据
                    if (!responeFile.exists()) {
                        responeFile.mkdirs();
                        responeModel = JsonToModel.generate(className + "Respone", apiAction.getRespone());
                        count += writeFile(responeModel, path);
                    } else {
                        has++;
                    }
                }

                //生成action
                String writeTempPath = actionsPath+"/"+alias+"/"+className+"Action.java";
                File file = new File(writeTempPath);
                if (!file.exists()) {
                    if(!file.getParentFile().exists()){
                        file.getParentFile().mkdir();
                    }
                    //返回数据

                    String domain = apiAction.getDomain();
                    String key = checkRootUrl(apiRoots,domain);

                    Map<String,Object> data = new HashMap<>();
                    data.put("domain",key);
                    data.put("package",usePackage);
                    data.put("alias",alias);
                    data.put("className",className);
                    String u = apiAction.getUrl();
                    String sp = "api/";
                    if(u.startsWith("api/")){
                        u = u.substring(sp.length());
                    }
                    data.put("url",u);
                    boolean hasRequest = !TextUtils.isEmpty(apiAction.getRequest());
                    boolean hasParam = !TextUtils.isEmpty(apiAction.getUrlParam());
                    boolean hasRespone =  !TextUtils.isEmpty(apiAction.getRespone());
                    data.put("hasRequest",hasRequest);
                    data.put("hasRespone",hasRespone);
                    data.put("hasParam",hasParam);
                    data.put("remark",apiAction.getRemark());
                    data.put("date", date);
                    data.put("method",apiAction.getMethod());
                    String tempPath = basePath+"template/";
                    String xxxaction = TemplateUtil.create(tempPath,"action.vm",data);
                    JsonXmlUtils.stringToFile(xxxaction, writeTempPath);
                    count ++;
                } else {
                    has++;
                }

                //生成task
                String writeTaskPath = actionsPath+"/"+alias+"/task/"+className+"Task.java";
                File file1 = new File(writeTaskPath);
                if (!file1.exists()) {
                    if(!file1.getParentFile().exists()){
                        file1.getParentFile().mkdir();
                    }
                    Map<String,Object> taskdata = new HashMap<>();
                    taskdata.put("package",usePackage);
                    taskdata.put("alias",alias);
                    taskdata.put("className",className);

                    boolean hasRequest = !TextUtils.isEmpty(apiAction.getRequest());
                    boolean hasRespone =  !TextUtils.isEmpty(apiAction.getRespone());
                    boolean hasParam =  !TextUtils.isEmpty(apiAction.getUrlParam());
                    if(hasRespone){
                        String firstKey = getFirstKey(responeModel);
                        taskdata.put("responeKey",firstKey);
                    }
                    taskdata.put("packages",packages);
                    taskdata.put("hasParam",hasParam);
                    taskdata.put("hasRequest",hasRequest);
                    taskdata.put("hasRespone",hasRespone);
                    taskdata.put("remark",apiAction.getRemark());
                    taskdata.put("date", date);
                    taskdata.put("method",apiAction.getMethod());

                    boolean hasDate = false;
                    if(hasRequest){
                        String requestKey = getFirstKey(requestModel);
                        String requestModelBean = getSetBeanStr(requestKey,requestModel);
                        if(requestModelBean.contains("new Date()")){
                            hasDate = true;
                        }
                        taskdata.put("requestModelBean",requestModelBean);
                        taskdata.put("requestKey",CommonUtil.firstToLowerCase(requestKey));
                    }
                    if(hasParam){
                        String paramKey = getFirstKey(urlModel);
                        String urlModelBean = getSetBeanStr(paramKey,urlModel);
                        if(urlModelBean.contains("new Date()")){
                            hasDate = true;
                        }
                        taskdata.put("urlModelBean",urlModelBean);
                        taskdata.put("paramKey",CommonUtil.firstToLowerCase(paramKey));
                    }
                    taskdata.put("hasDate",hasDate);
                    String taskPath = basePath+"template/";
                    String taskaction = TemplateUtil.create(taskPath,"task.vm",taskdata);
                    JsonXmlUtils.stringToFile(taskaction, writeTaskPath);
                    count ++;
                } else {
                    has++;
                }

                //生成使用task
                String writeUseTaskPath = actionsPath+"/"+alias+"/task/Use"+className+"Task.java";
                File file2 = new File(writeUseTaskPath);
                if (!file2.exists()) {
                    if(!file2.getParentFile().exists()){
                        file2.getParentFile().mkdir();
                    }
                    Map<String,Object> taskdata = new HashMap<>();
                    taskdata.put("package",usePackage);
                    taskdata.put("alias",alias);
                    taskdata.put("className",className);
                    taskdata.put("lowclassName",CommonUtil.firstToLowerCase(className));
                    String taskPath = basePath+"template/";
                    String taskaction = TemplateUtil.create(taskPath,"useTask.vm",taskdata);
                    JsonXmlUtils.stringToFile(taskaction, writeUseTaskPath);
                    count ++;
                } else {
                    has++;
                }

                if(onCallback!=null){
                    onCallback.onProgress(i,apiActions.size(),"正在生成中...进度:["+(i+1)+"/"+apiActions.size()+"],已生成"+count+"个java文件。");
                }
            } catch (Exception e) {
                e.printStackTrace();
                if(onCallback!=null){
                    onCallback.onError("执行失败:"+e.getMessage()+",ID="+apiAction.getId());
                }
                continue;
            }
        }
        if(onCallback!=null){
            onCallback.onSuccess("执行完成。共生成"+count+"个java文件。"+(has>0?"已存在"+has+"个文件夹。":"已全部生成。"));
        }
    }

    public interface OnCallback{
        void onProgress(int position,int size,String msg);
        void onSuccess(String msg);
        void onError(String msg);
    }

    /**
     * 生成所有属性的set值
     * @param firstKey
     * @param models
     * @return
     */
    private static String getSetBeanStr(String firstKey,Map<String, String> models){
        if(firstKey==null){
            return null;
        }
        return getCreateNewObjStr(2,firstKey,models);
    }

    /**
     *
     * @param models
     * @return
     */
    private static String getFirstKey(Map<String, String> models){
        if(models==null){
            return null;
        }
        String firstKey=null;
        for(String key:models.keySet()){
            if(key.endsWith("Request")
                    ||key.endsWith("Param")
                    ||key.endsWith("Respone")){
                firstKey = key;
                break;
            }
        }
        if(firstKey==null){
            return null;
        }
        return firstKey;
    }

    /**
     * 循环遍历属性
     * @param key
     * @param models
     * @return
     */
    private static String getCreateNewObjStr(int indent,String key,Map<String, String> models){
        String data = models.get(key);
        data =data.replaceAll(key+"\\{","");
        if(TextUtils.isEmpty(data)){
            return null;
        }
        String[] arr = data.split("\n");
        String str=getIndent(indent)+getNewObjStr(key);
        String paraKey = CommonUtil.firstToLowerCase(key);
        for(String s:arr){
            if(TextUtils.isEmpty(s)||s.startsWith("}")){
                continue;
            }
            String beiz = null;
            if(s.contains(":")){
                beiz = s.substring(s.indexOf(":")+1);
                s = s.substring(0,s.indexOf(":"));
            }
            String key2 = CommonUtil.getBetweenStr(s,"\\(","\\)");
            boolean isList = false;
            if(key2.startsWith("List<")){
                isList = true;
                key2 = CommonUtil.getBetweenStr(key2,"List\\<","\\>");
            }
            String v = models.get(key2);
            if(v!=null){
                String listKey = null;
                if(isList){
                    listKey = CommonUtil.firstToLowerCase(key2)+"List";
                    str+=getIndent(indent)+"List<"+key2+"> "+listKey+" = new ArrayList<>();\n";
                    str+=getIndent(indent)+"for(int i = 0;i<10;i++){\n";
                }
                str+=getCreateNewObjStr(isList?indent+1:indent,key2,models);
                String para = s.substring(0,s.indexOf("("));
                if(isList){
                    str+=getIndent(indent+1)+listKey+".add("+CommonUtil.firstToLowerCase(key2)+");\n";
                    str+=getIndent(indent)+"}\n";
                    str+= getIndent(indent)+paraKey+".set"+CommonUtil.firstToUpperCase(para)
                            +"("+listKey+");\n";
                }else{
                    str+=getIndent(indent)+paraKey+".set"+CommonUtil.firstToUpperCase(para)
                            +"("+CommonUtil.firstToLowerCase(key2)+");\n";
                }
            }else{
                String para = s.substring(0,s.indexOf("("));
                String value = getParamValue(key2,beiz);
                str+=getIndent(indent)+paraKey+".set"+CommonUtil.firstToUpperCase(para)+"("+value+");";
                if(!TextUtils.isEmpty(beiz)&&!"null".equals(beiz)){
                    str+="//"+beiz;
                }
                str+="\n";
            }
        }
        return str;
    }

    /**
     *  获取缩进
     * @param space
     * @return
     */
    private static String getIndent(int space){
        String sp = "";
        if(space>0){
            for(int i = 0 ;i<space;i++){
                sp+="\t";
            }
        }
        return sp;
    }

    /**
     *  获取属性默认值
     * @param type
     * @param beiz
     * @return
     */
    private static String getParamValue(String type,String beiz){
        String val = "\"\"";
        switch (type){
            case "String":
                if(!TextUtils.isEmpty(beiz)){
                    if(beiz.contains(",")) {
                        val = beiz.substring(0, beiz.indexOf(","));
                        if (beiz.contains("长度")) {
                            String lon = CommonUtil.getBetweenStr(beiz, "长度\\(0-", "\\)");
                            if(!TextUtils.isEmpty(lon)){
                                Integer ln = Integer.parseInt(lon);
                                if (ln != null && val.length()>ln) {
                                    val = val.substring(0, ln-1);
                                }
                            }
                        }
                    }
                    val="\""+val+"\"";
                }
                break;
            case "Integer":
                val="0";
                break;
            case "Date":
                //做转换 instant类型 实际是string
                val="DateUtil.toInstant(new Date())";
                break;
            case "Double":
                val="0.00";
                break;
            case "Float":
                val="0f";
                break;
            case "Long":
                val="0L";
                break;
        }
        return val;
    }

    /**
     *  创建对象
     * @param bean
     * @return
     */
    private static String getNewObjStr(String bean){
        return  bean+" "+CommonUtil.firstToLowerCase(bean)+" = new "+bean+"();\n";
    }
    /**
     * 写入java文件
     * @param responeModel
     * @param path
     * @throws IOException
     */
    private static int  writeFile(Map<String, String> responeModel,String path) throws IOException {
        int count = 0;
        for (String key : responeModel.keySet()) {
            String model = responeModel.get(key);
            ToBeanResult beanResult = ModelToBean.generate(model);
            Map<String, String> beans = beanResult.getBeans();
            for (String bk : beans.keySet()) {
                String javaFile = beans.get(bk);
                String p = path + bk + ".java";
                JsonXmlUtils.stringToFile(javaFile, p);
                count++;
            }
        }
        return count;
    }

    /**
     *  通过url设置类名
     * @param url
     * @return
     */
    private static String getClassNameByUrl(String url){
        String[] urSpit = url.split("/");
        String fileName="";
        if(urSpit.length>2){
            String pr = urSpit[urSpit.length-2];
            if(pr.length()>2){
                pr = pr.substring(0,2);
            }
            fileName+=transformName(pr);
        }
        fileName+=transformName(urSpit[urSpit.length-1]);
        fileName = replaceAll(fileName);
        return fileName;
    }

    /**
     *  通过url设置包名
     * @param url
     * @return
     */
    private static String getClassPathByUrl(String url){
        String[] urSpit = url.split("/");
        int p = 3;
        if(urSpit[urSpit.length-1].startsWith("{")){
           p--;
        }
        String fileName="";
        if(urSpit.length>p){
            String pr = urSpit[urSpit.length-p];
            p--;
            if(pr.length()>2){
                pr = pr.substring(0,2);
            }
            fileName+=pr;
        }
        if(urSpit.length>p){
            String pr = urSpit[urSpit.length-p];
            if(pr.length()>2){
                pr =  pr.substring(0,2);
            }
            fileName+=pr;
        }
        fileName+=urSpit[urSpit.length-1];
        fileName = replaceAll(fileName);
        return fileName;
    }

    /**
     * 去掉一些特殊字符
     * @param str
     * @return
     */
    private static String replaceAll(String str){
        return str.replaceAll("\\!|\\-|_|\\{|\\}","");
    }

    /**
     * 首字母大写
     * @param originName
     * @return
     */
    private static String transformName(String originName) {
        if (originName != null && originName.length() > 0) {
            return originName.substring(0, 1).toUpperCase() + originName.substring(1);
        }
        return originName;
    }

    /**
     * 根据根目录获取对应的root key
     * @param apiRoots
     * @param domain
     * @return
     */
    private static String checkRootUrl(List<ApiRoot> apiRoots,String domain){
        if(domain.contains("/")){
            domain = domain.substring(domain.lastIndexOf("/"));
        }
        for(ApiRoot apiRoot:apiRoots){
            if(apiRoot.getUrl().contains(domain)
                    ||!TextUtils.isEmpty(apiRoot.getTestUrl())&&apiRoot.getTestUrl().contains(domain)
                    ||!TextUtils.isEmpty(apiRoot.getDevUrl())&&apiRoot.getDevUrl().contains(domain)
            ){
                return apiRoot.getKey();
            }
        }
        return "ROOT_DEFAULT";
    }
}
